using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Application = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace AutoCAD_CSharp_plug_in3.Chap02
{
    public static class EconomicBottleLayout
    {
        public static void Handle()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

            // 选择管线
            if (!SelectPipelines(ed, out var lineObjectId)) return;

            // 获取输入参数
            if (!GetParameters(ed, out var parameters)) return;

            // 拆分线段
            if (!DecomposeToOrderedLineSegments(db, lineObjectId, out var lineSegments)) return;

            // 优化瓶组布局
            var result = SmartOptimizationEngine.OptimizeLayout(lineSegments, parameters);
            result.ObjectIds = lineObjectId;

            if (result.Succeed())
            {
                // 绘制
                DrawOptimizationResult(db, result);
                // 显示结果信息
                ShowOptimizationResults(ed, result);
            }
            else
            {
                Application.ShowAlertDialog($"\n总利用长度: {result.TotalPipelineLength:F2}mm");
            }
        }

        private static bool SelectPipelines(Editor ed, out List<ObjectId> lineObjectId)
        {
            lineObjectId = new List<ObjectId>();

            // 选择模式：多条连续的直线 或 一条多段线
            PromptKeywordOptions modeOpts = new PromptKeywordOptions("\n请选择模式:")
            {
                AllowArbitraryInput = false,
                AllowNone = false
            };
            modeOpts.Keywords.Add("Line", "L", "多条连续的直线");
            modeOpts.Keywords.Add("Polyline", "P", "一条多段线");
            modeOpts.Message = "\n请选择 [多条连续的直线(L)/一条多段线(P)]: ";

            PromptResult modeRes = ed.GetKeywords(modeOpts);
            if (modeRes.Status != PromptStatus.OK)
                return false;

            // 设置选择选项
            PromptSelectionOptions opts = new PromptSelectionOptions
            {
                AllowDuplicates = false,
                RejectObjectsFromNonCurrentSpace = true,
                RejectObjectsOnLockedLayers = true,
                SingleOnly = false,
                SinglePickInSpace = true
            };

            TypedValue[] filterList;
            switch (modeRes.StringResult)
            {
                case "Polyline":
                    opts.MessageForAdding = "\n请选择一条多段线（管线）:";
                    filterList = new[] { new TypedValue((int)DxfCode.Start, "LWPOLYLINE") };
                    break;
                case "Line":
                    opts.MessageForAdding = "\n请选择多条连续的直线（管线）:";
                    filterList = new[] { new TypedValue((int)DxfCode.Start, "LINE") };
                    break;
                default:
                    return false;
            }

            PromptSelectionResult result = ed.GetSelection(opts, new SelectionFilter(filterList));
            if (result.Status != PromptStatus.OK)
                return false;
            lineObjectId.AddRange(result.Value.GetObjectIds());
            return lineObjectId.Count > 0;
        }

        private static bool GetParameters(Editor ed, out LayoutParameters parameters)
        {
            parameters = new LayoutParameters();

            // 钢瓶型号
            PromptIntegerResult pir1 = ed.GetInteger(CreatePromptOptions("\n请选择钢瓶型号(1:80L 2:90L):", 1, 2));
            if (pir1.Status != PromptStatus.OK) return false;
            parameters.BottleType = pir1.Value;

            // 单双排
            PromptIntegerResult pir2 = ed.GetInteger(CreatePromptOptions("\n请选择排布方式(1:单排 2:双排):", 1, 2));
            if (pir2.Status != PromptStatus.OK) return false;
            parameters.Arrangement = pir2.Value - 1; // 转换为0/1 匹配数据：PzParamConfig.InitPzParams

            // 总钢瓶数
            const int maxBottles = 999; // 设置一个合理的上限,最大钢瓶数范围
            PromptIntegerResult pir3 = ed.GetInteger(CreatePromptOptions($"\n请输入总钢瓶数(1-{maxBottles}):", 1, maxBottles));
            if (pir3.Status != PromptStatus.OK) return false;
            parameters.TotalBottles = pir3.Value;

            // 框架间距
            PromptDoubleResult pdr = ed.GetDouble(new PromptDoubleOptions("\n请输入框架间距(mm):")
            {
                AllowNegative = false,
                AllowZero = true
            });
            if (pdr.Status != PromptStatus.OK) return false;
            parameters.FrameSpacing = pdr.Value;

            // 前置距离
            PromptDoubleResult pdr2 = ed.GetDouble(new PromptDoubleOptions("\n请输入前置距离(mm):")
            {
                AllowNegative = false,
                AllowZero = true
            });
            if (pdr2.Status != PromptStatus.OK) return false;
            parameters.PreDistance = pdr2.Value;
            return true;
        }

        private static PromptIntegerOptions CreatePromptOptions(string message, int min, int max)
        {
            var pio = new PromptIntegerOptions(message)
            {
                AllowZero = false, // 不允许0
                AllowNegative = false, // 不允许负数
                AllowNone = false, // 不允许空输入
                DefaultValue = min, // 默认值设为1
                UseDefaultValue = true, // 使用默认值
                // 设置允许的值范围
                LowerLimit = min,
                UpperLimit = max
            };
            return pio;
        }

        /// <summary>
        /// 拆分线段，处理多条连续的直线或者是一条多段线
        /// </summary>
        private static bool DecomposeToOrderedLineSegments(Database db, List<ObjectId> lineObjectId,
            out List<OrderedLineSegment> segments)
        {
            var curves = new List<Curve>(lineObjectId.Count);
            using (var trans = db.TransactionManager.StartTransaction())
            {
                foreach (var lineId in lineObjectId)
                {
                    Entity ent = (Entity)trans.GetObject(lineId, OpenMode.ForRead);
                    if (ent is Curve curve)
                        curves.Add(curve);
                }

                trans.Commit();
            }

            var rawSegments = new List<OrderedLineSegment>(curves.Count);
            foreach (var curve in curves)
            {
                switch (curve)
                {
                    case Line line:
                        rawSegments.Add(new OrderedLineSegment(line.StartPoint, line.EndPoint,
                            line.LayerId, line.ColorIndex, line.LineWeight));
                        break;

                    case Polyline polyline:
                        int count = polyline.NumberOfVertices - 1;
                        for (int i = 0; i < count; i++)
                        {
                            // 使用 GetLineSegment2dAt(i) 点查询
                            var plp = polyline.GetLineSegment2dAt(i);
                            var segment = new OrderedLineSegment(
                                new Point3d(plp.StartPoint.X, plp.StartPoint.Y, 0),
                                new Point3d(plp.EndPoint.X, plp.EndPoint.Y, 0),
                                polyline.LayerId, polyline.ColorIndex, polyline.LineWeight);
                            rawSegments.Add(segment);
                        }

                        break;
                }
            }

            segments = new List<OrderedLineSegment>(rawSegments.Count);
            var remaining = new List<OrderedLineSegment>(rawSegments);
            // 以第一条作为起点
            segments.Add(remaining[0]);
            remaining.RemoveAt(0);

            // 优先接在尾部，其次接在头部；都接不上则开启新链
            while (remaining.Count > 0)
            {
                // 尝试接到尾部
                var tail = segments[segments.Count - 1];
                var tailEnd = tail.GetPointAt(tail.Length);

                int idx = -1;
                bool reverse = false;
                for (int i = 0; i < remaining.Count; i++)
                {
                    var cand = remaining[i];
                    var candStart = cand.GetPointAt(0);
                    var candEnd = cand.GetPointAt(cand.Length);

                    if (IsClose(tailEnd, candStart))
                    {
                        idx = i;
                        break;
                    }

                    if (IsClose(tailEnd, candEnd))
                    {
                        idx = i;
                        reverse = true;
                        break;
                    }
                }

                if (idx >= 0)
                {
                    var next = remaining[idx];
                    remaining.RemoveAt(idx);
                    if (reverse)
                    {
                        // 反转候选线段方向
                        segments.Add(new OrderedLineSegment(next.GetPointAt(next.Length), next.GetPointAt(0),
                            next.LayerId, next.ColorIndex, next.LineWeight));
                    }
                    else
                    {
                        segments.Add(next);
                    }

                    continue;
                }

                // 尝试接到头部
                var head = segments[0];
                var headStart = head.GetPointAt(0);

                int idx2 = -1;
                bool reverse2 = false;
                for (int i = 0; i < remaining.Count; i++)
                {
                    var cand = remaining[i];
                    var candStart = cand.GetPointAt(0);
                    var candEnd = cand.GetPointAt(cand.Length);

                    if (IsClose(candEnd, headStart))
                    {
                        idx2 = i;
                        break;
                    }

                    if (IsClose(candStart, headStart))
                    {
                        idx2 = i;
                        reverse2 = true;
                        break;
                    }
                }

                if (idx2 >= 0)
                {
                    var next = remaining[idx2];
                    remaining.RemoveAt(idx2);
                    if (reverse2)
                    {
                        segments.Insert(0, new OrderedLineSegment(next.GetPointAt(next.Length), next.GetPointAt(0),
                            next.LayerId, next.ColorIndex, next.LineWeight));
                    }
                    else
                    {
                        segments.Insert(0, next);
                    }

                    continue;
                }

                segments.Add(remaining[0]);
                remaining.RemoveAt(0);
            }

            return segments.Count > 0;

            // 判断两点是否相近（容差）
            bool IsClose(Point3d a, Point3d b, double tol = 1e-6) => a.DistanceTo(b) <= tol;
        }


        private static void DrawOptimizationResult(Database db, OptimizationResult result)
        {
            using (var trans = db.TransactionManager.StartTransaction())
            {
                try
                {
                    using (Application.DocumentManager.MdiActiveDocument.LockDocument())
                    {
                        // 批量删除对象
                        foreach (var objectId in result.ObjectIds)
                        {
                            var entity = trans.GetObject(objectId, OpenMode.ForWrite);
                            entity.Erase();
                        }

                        var bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);
                        var btr = (BlockTableRecord)trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                        // 批量添加实体
                        var entitiesToAdd = new List<Entity>();
                        foreach (var placement in result.Placements)
                        {
                            entitiesToAdd.AddRange(placement.BottleGroupLegend);
                            entitiesToAdd.AddRange(placement.ObjectLegend);
                        }

                        foreach (var entity in entitiesToAdd)
                        {
                            btr.AppendEntity(entity);
                            trans.AddNewlyCreatedDBObject(entity, true);
                        }
                    }

                    trans.Commit();
                }
                catch (Exception)
                {
                    trans.Abort();
                }
            }
        }

        private static void ShowOptimizationResults(Editor ed, OptimizationResult result)
        {
            ed.WriteMessage("\n=== 瓶组布局结果 ===");
            ed.WriteMessage($"\n使用的瓶组数: {result.TotalGroup}");
            ed.WriteMessage($"\n实际放置瓶子数: {result.TotalBottles}");
            ed.WriteMessage($"\n总管线利用长度: {result.TotalPipelineLength:F2}mm");
            ed.WriteMessage($"\n管线利用率: {result.PipelineUtilizationRate:P1}");
        }
    }

    /// <summary>
    /// 布局参数类
    /// </summary>
    public class LayoutParameters
    {
        public int BottleType { get; set; } // 1=80L, 2=90L
        public int Arrangement { get; set; } // 0=单排, 1=双排
        public int TotalBottles { get; set; } // 总钢瓶数
        public double FrameSpacing { get; set; } // 框架间距
        public double PreDistance { get; set; } // 前置距离

        public List<BottleGroup> GetOptimizedBottleGroups()
        {
            return PzParamConfig.GetConfigs()
                .Where(p => p.RL == (BottleType == 1 ? 80 : 90) && p.dsp == Arrangement)
                .Select(p => new BottleGroup(p))
                .OrderByDescending(group => group.FrameLength)
                .ThenByDescending(group => group.BottleCount)
                .ToList();
        }
    }

    /// <summary>
    /// 有序线段类
    /// </summary>
    public class OrderedLineSegment
    {
        // 原始线段起点
        public Point3d StartPoint { get; }

        // 原始线段终点
        public Point3d EndPoint { get; }

        public int ColorIndex { get; }

        public LineWeight LineWeight { get; }

        public ObjectId LayerId { get; }

        // 单位化方向向量
        public Vector3d Direction => (EndPoint - StartPoint).GetNormal();

        public double Length => StartPoint.DistanceTo(EndPoint);

        // 线段与X轴正方向的夹角，弧度制
        public double Angle => Math.Atan2(EndPoint.Y - StartPoint.Y, EndPoint.X - StartPoint.X);

        public OrderedLineSegment(Point3d startPoint, Point3d endPoint, ObjectId layerId,
            int colorIndex, LineWeight lineWeight)
        {
            StartPoint = startPoint;
            EndPoint = endPoint;
            LayerId = layerId;
            ColorIndex = colorIndex;
            LineWeight = lineWeight;
        }

        /// <summary>
        /// 获取线段上指定距离的点
        /// </summary>
        /// <param name="distance">从起始点开始的距离</param>
        /// <returns>指定距离处的三维点</returns>
        public Point3d GetPointAt(double distance)
        {
            if (distance <= 0) return StartPoint;
            if (distance >= Length) return EndPoint;

            return StartPoint + Direction * distance;
        }
    }

    /// <summary>
    /// 瓶组信息类
    /// </summary>
    public class BottleGroup
    {
        public int BottleType { get; } // 1=80L, 2=90L
        public int Arrangement { get; } // 0=单排, 1=双排
        public int BottleCount { get; } // 瓶子数量
        public int Rank { get; set; } // 排数
        public double FrameWidth { get; set; } // 框架宽度
        public double FrameLength { get; } // 框架长度

        public BottleGroup(PzParam param)
        {
            BottleType = param.RL == 80 ? 1 : 2;
            Arrangement = param.dsp;
            BottleCount = param.num;
            Rank = param.row;
            FrameWidth = param.leftLength;
            FrameLength = param.rightLength;
        }

        public BottleGroup()
        {
            BottleType = -1;
            Arrangement = -1;
            BottleCount = 0;
            Rank = 0;
            FrameWidth = 0;
            FrameLength = 0;
        }

        public bool IsNotEmptyGroup()
        {
            return BottleType != -1 && Arrangement != -1;
        }

        public override string ToString()
        {
            if (BottleType == -1 && Arrangement == -1)
            {
                return "空瓶组";
            }

            return $"{(BottleType == 1 ? "80L" : "90L")}-{(Arrangement == 0 ? "单排" : "双排")}-{Rank}排-{BottleCount}瓶";
        }
    }

    /// <summary>
    /// 瓶组放置信息类
    /// </summary>
    public class BottleGroupPlacement
    {
        // 放置的瓶组信息
        public BottleGroup BottleGroup { get; }

        // 瓶组在管线上的具体位置点
        public Point3d Position { get; }

        // 瓶组所属的管线段对象
        public OrderedLineSegment Segment { get; }

        // 瓶组距离所属线段起点的距离（毫米）
        public double DistanceFromStart { get; set; }

        // 瓶组图例
        public List<Entity> BottleGroupLegend { get; }

        public List<Entity> ObjectLegend { get; }

        public BottleGroupPlacement(BottleGroup group,
            OrderedLineSegment segment, double distanceFromStart)
        {
            BottleGroupLegend = Ig541Action.GenEntity(
                group.BottleType,
                group.Arrangement + 1,
                1,
                group.BottleCount
            );

            BottleGroup = group;
            // 计算放置位置
            Position = segment.GetPointAt(distanceFromStart);
            Segment = segment;
            DistanceFromStart = distanceFromStart;
            ObjectLegend = new List<Entity>();
            GenerateBottleGroup();
        }

        public bool IsNotEmpty()
        {
            return BottleGroupLegend.Count != 0;
        }

        public BottleGroupPlacement(OrderedLineSegment segment)
        {
            BottleGroup = new BottleGroup();
            Segment = segment;
            BottleGroupLegend = new List<Entity>();
            ObjectLegend = new List<Entity>();
            Add(segment.StartPoint, segment.EndPoint);
        }

        public void Add(Point3d connectionStart, Point3d connectionEnd)
        {
            // 创建连接线，保持原线段的属性
            var connectionLine = new Line(connectionStart, connectionEnd)
            {
                LayerId = Segment.LayerId,
                ColorIndex = Segment.ColorIndex,
                LineWeight = Segment.LineWeight
            };
            // 添加连接线到
            ObjectLegend.Add(connectionLine);
        }

        public void NextStartDistance(Curve curve, out double currentDistance)
        {
            Point3d point = Point3d.Origin;
            double minDist = double.MaxValue;

            foreach (Point3d corner in GetBoundingBoxVertices())
            {
                Point3d ptOnLine = curve.GetClosestPointTo(corner, false);
                double distance = corner.DistanceTo(ptOnLine);

                if (distance < minDist)
                {
                    minDist = distance;
                    point = ptOnLine;
                }
            }

            currentDistance = Segment.EndPoint.DistanceTo(point);
        }

        public void NextStartDistance(out double currentDistance)
        {
            currentDistance = BottleGroup.FrameWidth / 2;
        }

        /// <summary>
        /// 生成瓶组图形
        /// </summary>
        private void GenerateBottleGroup()
        {
            // 计算集流管起点
            var pipelinePoint = CalPipelinePoint(BottleGroup, BottleGroupLegend);

            // 计算瓶组位置
            Matrix3d rotation = Matrix3d.Rotation(Segment.Angle, Vector3d.ZAxis, Point3d.Origin);
            Matrix3d translation =
                Matrix3d.Displacement(Position - pipelinePoint.TransformBy(rotation));
            Matrix3d combined = rotation.PreMultiplyBy(translation);
            foreach (var item in BottleGroupLegend)
            {
                item.TransformBy(combined);
            }
        }

        /// <summary>
        /// 计算集流管线偏移量
        /// </summary>
        private static Point3d CalPipelinePoint(BottleGroup bottleGroup, List<Entity> entities)
        {
            Point3d jlgStartPoint = Point3d.Origin;
            foreach (Entity entity in entities)
            {
                if (!(entity is Line line) || !Ig541Action.IsJiLiuGuan(line,
                        bottleGroup.BottleType, bottleGroup.Arrangement + 1, 1, bottleGroup.BottleCount)) continue;
                jlgStartPoint = line.StartPoint;
                break;
            }

            return jlgStartPoint;
        }

        /// <summary>
        /// 获取外框的所有顶点
        /// </summary>
        /// <returns>外框的四个顶点（逆时针）：左下、右下、右上、左上</returns>
        private List<Point3d> GetBoundingBoxVertices()
        {
            double minX = double.MaxValue;
            double minY = double.MaxValue;
            double maxX = double.MinValue;
            double maxY = double.MinValue;

            foreach (Entity ent in BottleGroupLegend)
            {
                // 获取实体的几何范围
                Extents3d extents = ent.GeometricExtents;

                // 更新最小最大值
                if (extents.MinPoint.X < minX) minX = extents.MinPoint.X;
                if (extents.MinPoint.Y < minY) minY = extents.MinPoint.Y;
                if (extents.MaxPoint.X > maxX) maxX = extents.MaxPoint.X;
                if (extents.MaxPoint.Y > maxY) maxY = extents.MaxPoint.Y;
            }

            // 构建外框的四个顶点（逆时针）
            List<Point3d> vertices = new List<Point3d>
            {
                new Point3d(minX, minY, 0), // 左下
                new Point3d(maxX, minY, 0), // 右下
                new Point3d(maxX, maxY, 0), // 右上
                new Point3d(minX, maxY, 0) // 左上
            };

            return vertices;
        }
    }

    /// <summary>
    /// 优化结果类
    /// </summary>
    public class OptimizationResult
    {
        public double TotalAvailableLength { get; set; }
        public int TotalBottles { get; set; }
        public List<ObjectId> ObjectIds { get; set; } = new List<ObjectId>();
        public List<BottleGroupPlacement> Placements { get; } = new List<BottleGroupPlacement>();


        public int TotalGroup => Placements.Count(p => p.BottleGroup.IsNotEmptyGroup());
        private int TotalUsedBottles => Placements.Sum(p => p.BottleGroup.BottleCount);
        public double TotalPipelineLength => Placements.Sum(p => p.BottleGroup.FrameLength);

        public double PipelineUtilizationRate =>
            TotalAvailableLength > 0 ? TotalPipelineLength / TotalAvailableLength : 0;

        public bool Succeed() => TotalUsedBottles == TotalBottles;
    }

    /// <summary>
    /// 优化瓶组布局
    /// </summary>
    public static class SmartOptimizationEngine
    {
        public static OptimizationResult OptimizeLayout(List<OrderedLineSegment> segments, LayoutParameters parameters)
        {
            // 带分配的总钢瓶数
            var remainingBottles = parameters.TotalBottles;

            // 框架间距
            var frameSpacing = parameters.FrameSpacing;

            // 前置距离
            var preDistance = parameters.PreDistance;

            var result = new OptimizationResult
            {
                // 总的线段长度
                TotalAvailableLength = segments.Sum(s => s.Length),
                // 总需要铺设钢瓶数
                TotalBottles = parameters.TotalBottles
            };

            // 找到当前瓶组处理规则集合
            var availableGroups = parameters.GetOptimizedBottleGroups();

            var placements = OptimizeSegmentsRecursive(
                segments, 0, availableGroups, remainingBottles, frameSpacing, preDistance);
            result.Placements.AddRange(placements);

            return result;
        }

        /// <summary>
        /// 递归线段布局
        /// </summary>
        /// <param name="segments">所有线段列表</param>
        /// <param name="currentIndex">当前处理的线段索引</param>
        /// <param name="availableGroups">可用的瓶组规格列表</param>
        /// <param name="remainingBottles">剩余待分配的瓶子数</param>
        /// <param name="frameSpacing">框架间距</param>
        /// <param name="startDistance">当前线段上的起始偏移（与上段连续）</param>
        /// <returns>所有瓶组放置结果</returns>
        private static List<BottleGroupPlacement> OptimizeSegmentsRecursive(
            List<OrderedLineSegment> segments,
            int currentIndex,
            List<BottleGroup> availableGroups,
            int remainingBottles,
            double frameSpacing,
            double startDistance)
        {
            var placements = new List<BottleGroupPlacement>();

            // 没有更多线段或没有剩余瓶子
            if (currentIndex >= segments.Count || remainingBottles <= 0)
            {
                return placements;
            }

            var currentSegment = segments[currentIndex];

            // 在当前线段上放置瓶组
            var currentPlacements = OptimizeSingleSegment(
                currentSegment, availableGroups, remainingBottles, frameSpacing, startDistance);
            if (currentPlacements.Count == 0)
            {
                var placement = new BottleGroupPlacement(currentSegment);
                placements.Add(placement);
            }
            else
            {
                placements.AddRange(currentPlacements);
                ConnectionLine(currentPlacements);
            }

            // 计算当前线段使用的瓶子数
            var usedBottles = currentPlacements.Sum(p => p.BottleGroup.BottleCount);
            var newRemainingBottles = remainingBottles - usedBottles;

            var nextIndex = currentIndex + 1;
            // 若没有后续线段，结束
            if (nextIndex >= segments.Count || newRemainingBottles <= 0)
            {
                if (newRemainingBottles <= 0)
                {
                    for (var i = nextIndex; i < segments.Count; i++)
                    {
                        var otherSegment = segments[i];
                        var placement = new BottleGroupPlacement(otherSegment);
                        placements.Add(placement);
                    }
                }

                return placements;
            }

            // 为下一条连续的线段重新计算起始位置
            if (placements.Count > 0)
            {
                BottleGroupPlacement bgp = placements[placements.Count - 1];
                if (bgp.IsNotEmpty())
                {
                    // 计算最后一个瓶组到下一段的最近投影距离，作为下一段起始偏移
                    var nextSegment = segments[nextIndex];
                    bgp.NextStartDistance(new Line(nextSegment.StartPoint, nextSegment.EndPoint), out startDistance);
                }
                else
                {
                    startDistance = 0.0;
                }
            }

            // 递归处理下一条线段（承接偏移）
            var nextPlacements = OptimizeSegmentsRecursive(
                segments, nextIndex, availableGroups, newRemainingBottles, frameSpacing, startDistance);

            placements.AddRange(nextPlacements);

            return placements;
        }

        /// <summary>
        /// 优化单个线段的布局
        /// </summary>
        private static List<BottleGroupPlacement> OptimizeSingleSegment(OrderedLineSegment segment,
            List<BottleGroup> availableGroups, int maxBottles, double frameSpacing, double currentDistance)
        {
            var placements = new List<BottleGroupPlacement>();
            // 当前线的长度
            var remainingLength = segment.Length;
            // 剩余的瓶子
            var remainingBottles = maxBottles;
            // 最小框架长度
            var minFrameLength = availableGroups.Last().FrameLength;

            if (currentDistance > 0)
            {
                remainingLength -= currentDistance;
            }

            // 当前线计算逻辑
            while (remainingLength >= minFrameLength && remainingBottles > 0)
            {
                if (!EvaluateBottleGroup(availableGroups, frameSpacing, remainingLength,
                        remainingBottles,
                        minFrameLength, out var bestGroup)) break;


                var placement = new BottleGroupPlacement(bestGroup, segment, currentDistance);
                placements.Add(placement);

                // 扣减瓶子数
                remainingBottles -= bestGroup.BottleCount;

                // 增加间距
                var usedLength = bestGroup.FrameLength;
                usedLength += frameSpacing;

                remainingLength -= usedLength;
                currentDistance += usedLength;
            }

            return placements;
        }

        private static bool EvaluateBottleGroup(List<BottleGroup> availableGroups, double frameSpacing,
            double remainingLength, int remainingBottles, double minFrameLength, out BottleGroup bestGroup)
        {
            bestGroup = null;

            List<BottleGroup> used = new List<BottleGroup>(10);

            // 阶段1：可能放下最大框架长度
            do
            {
                var bg1 = availableGroups
                    .Where(group => group.FrameLength <= remainingLength && group.BottleCount <= remainingBottles)
                    .OrderByDescending(group => group.BottleCount)
                    .ToList();
                BottleGroup g2 = bg1.FirstOrDefault();

                if (g2 == null) continue;
                used.Add(g2);

                remainingLength = remainingLength - g2.FrameLength - frameSpacing;
                remainingBottles -= g2.BottleCount;
            } while (remainingLength >= minFrameLength && remainingBottles > 0);


            if (used.Count < 1) return false;
            {
                // 当前被计算出来的分布情况
                var sum = used.Sum(p => p.Rank);
                // 如果>5排同时< 9排的组合时候，需要重新计算 
                if (sum > 5 && sum < 9)
                {
                    // 阶段2：均衡分组使用相同排数的组合（例如3排+3排，而非5排+1排）
                    var rank = Math.Round(sum / 2.0);

                    var bottleGroups = availableGroups
                        .Where(group => group.Rank <= rank)
                        .OrderByDescending(group => group.BottleCount)
                        .ToList();
                    bestGroup = bottleGroups
                        .First();
                }
                else
                {
                    bestGroup = used.First();
                }

                return true;
            }
        }

        private static void ConnectionLine(List<BottleGroupPlacement> placements)
        {
            // 为瓶组之间添加连接线，确保管线的连续性
            for (var i = 0; i < placements.Count; i++)
            {
                var current = placements[i];

                // 计算当前瓶组连接起点 起始点加长度
                Point3d connectionStart;
                Point3d connectionEnd;
                if (i == 0 && current.DistanceFromStart > 0)
                {
                    connectionStart = current.Segment.StartPoint;
                    current.Add(connectionStart, current.Position);
                }

                // 计算当前瓶组连接起点 起始点加长度
                connectionStart = current.Position +
                                  current.Segment.Direction * current.BottleGroup.FrameLength;

                // end point 
                if (i < placements.Count - 1)
                {
                    // 连接到下一个瓶组的起点
                    var nextPlacement = placements[i + 1];
                    connectionEnd = nextPlacement.Position;
                }
                else
                {
                    // 最后一个瓶组连接到线段终点
                    connectionEnd = current.Segment.EndPoint;
                }

                current.Add(connectionStart, connectionEnd);
            }
        }
    }
}